The Zambian Kwacha has seen a great deal of movements against the Dollar over the past 10 years, the purpose of this notebook is to explore and analyse the movements in the exchange rates over that past ten years to gain insight in the currency movements. This analysis will solely focus on the movements between the Zambian Kwacha (ZMW) against the United states Dollar ($).
Currency exchange rate forecasting means predicting future fluctuations in the value of one currency against another. It involves the use of historical data, economic indicators, and mathematical models to make accurate predictions about the direction and magnitude of exchange rate movements. This portion of the project will be focused on changes in the exchange rate and the forecasting is in the next section.
The source of the data used for my analysis is from the Zambian Central bank:The Bank of Zambia- USD/ZMW exchange rates
The results of this analysis can be used by policy makers and investors to manage the exchange rate risk of conducting business in zambia
#import the relevant Libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
import plotly.io as pio
from plotly.subplots import make_subplots
raw_data=pd.read_csv(r"C:\Users\Namukaba Katambo\Desktop\NK\Datasets for practice\DAILY_RATES 07182023.csv")
raw_data.head()
| DATE | TIME | BUYING RATE | MID RATE | SELLING RATE | |
|---|---|---|---|---|---|
| 0 | 1/2/2013 | 3:30:00 PM | 5.24 | 5.250000 | 5.260000 |
| 1 | 1/2/2013 | 12:30:00 PM | 5.217777778 | 5.227778 | 5.237778 |
| 2 | 1/2/2013 | 9:30:00 AM | 5.161111111 | 5.171111 | 5.181111 |
| 3 | 1/3/2013 | 9:30:00 AM | 5.259722222 | 5.269722 | 5.279722 |
| 4 | 1/3/2013 | 12:30:00 PM | 5.238611111 | 5.248611 | 5.258611 |
#number of columns and rows
raw_data.shape
(7836, 5)
#creating a copy of the dataframe
data=raw_data.copy()
data.shape
(7836, 5)
#changing the text format of the column names
data.columns = data.columns.str.capitalize()
data.head()
| Date | Time | Buying rate | Mid rate | Selling rate | |
|---|---|---|---|---|---|
| 0 | 1/2/2013 | 3:30:00 PM | 5.24 | 5.250000 | 5.260000 |
| 1 | 1/2/2013 | 12:30:00 PM | 5.217777778 | 5.227778 | 5.237778 |
| 2 | 1/2/2013 | 9:30:00 AM | 5.161111111 | 5.171111 | 5.181111 |
| 3 | 1/3/2013 | 9:30:00 AM | 5.259722222 | 5.269722 | 5.279722 |
| 4 | 1/3/2013 | 12:30:00 PM | 5.238611111 | 5.248611 | 5.258611 |
#Checking for missing values
data.isnull().sum()
Date 0 Time 0 Buying rate 0 Mid rate 0 Selling rate 0 dtype: int64
#viewing the data types in the dataframe
data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 7836 entries, 0 to 7835 Data columns (total 5 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Date 7836 non-null object 1 Time 7836 non-null object 2 Buying rate 7836 non-null object 3 Mid rate 7836 non-null float64 4 Selling rate 7836 non-null float64 dtypes: float64(2), object(3) memory usage: 306.2+ KB
#Checking the details of the numerical data base
data.describe()
| Mid rate | Selling rate | |
|---|---|---|
| count | 7836.000000 | 7836.000000 |
| mean | 12.230194 | 12.249947 |
| std | 5.088820 | 5.093707 |
| min | 5.171111 | 5.181111 |
| 25% | 8.335764 | 8.345764 |
| 50% | 10.970278 | 10.986944 |
| 75% | 16.966953 | 16.991953 |
| max | 22.669275 | 22.694119 |
#changing the format of the date column and adding a month and year column for better analysis of the exchange rate movements
data["Date"] = pd.to_datetime(data["Date"], format = "%m/%d/%Y")
data['Year'] = data['Date'].dt.year
data["Month"] = data["Date"].dt.month
data.head()
| Date | Time | Buying rate | Mid rate | Selling rate | Year | Month | |
|---|---|---|---|---|---|---|---|
| 0 | 2013-01-02 | 3:30:00 PM | 5.24 | 5.250000 | 5.260000 | 2013 | 1 |
| 1 | 2013-01-02 | 12:30:00 PM | 5.217777778 | 5.227778 | 5.237778 | 2013 | 1 |
| 2 | 2013-01-02 | 9:30:00 AM | 5.161111111 | 5.171111 | 5.181111 | 2013 | 1 |
| 3 | 2013-01-03 | 9:30:00 AM | 5.259722222 | 5.269722 | 5.279722 | 2013 | 1 |
| 4 | 2013-01-03 | 12:30:00 PM | 5.238611111 | 5.248611 | 5.258611 | 2013 | 1 |
Below graph shows the overrall exchange rate movements over the defined period(2013-2023)
figure = px.line(data, x="Date",
y="Selling rate",
title='USD/KMW Conversion Rate over the years 2013-2023')
figure.show()
The chart below will show the decomposition of exchange rates into seasonal, trend, and residual components.
1.The trend component represents the long-term movement or the overall direction of the exchange rate. It shows the underlying growth or decline in the exchange rate that is not attributable to seasonal or random fluctuations
2.The seasonal component captures the regular and repeated patterns that occur at fixed intervals, such as monthly, quarterly, or yearly cycles
3.The residual component, represents the unexplained variation in the data after accounting for the trend and seasonal components.
import statsmodels.api as sm
# Perform seasonal decomposition using statsmodels
decomposition = sm.tsa.seasonal_decompose(data['Selling rate'], model='additive', period=12)
# Extract the components: trend, seasonal, and residual
trend = decomposition.trend
seasonal = decomposition.seasonal
residual = decomposition.resid
# Create the seasonal decomposition chart using Plotly
fig = go.Figure()
fig.add_trace(go.Scatter(x=data['Date'], y=trend, mode='lines', name='Trend'))
fig.add_trace(go.Scatter(x=data['Date'], y=seasonal, mode='lines', name='Seasonal'))
fig.add_trace(go.Scatter(x=data['Date'], y=residual, mode='lines', name='Residual'))
fig.update_layout(title='Seasonal Decomposition of Exchange Rate',
xaxis_title='Date',
yaxis_title='Exchange Rate',
xaxis=dict(tickangle=-45),
template='plotly_white')
fig.show()
-From the chart we can observe a general upward trend in the exchange rate meaning generally theres a depreciation of the kwacha against the dollar
-the seasonal component is not defined.
-There is a large residual component during certain periods suggesting that there are significant unpredictable movements in the exchange rate that are not accounted for by the trend and seasonality.
Calculating the percentage growth/change of the USD/ZMW over the past 10 years
yearly_rate_change = data.groupby('Year').agg({'Selling rate': lambda x: (x.iloc[-1]-x.iloc[0])/x.iloc[-1]*100})
fig = go.Figure()
fig.add_trace(go.Bar(x=yearly_rate_change.index,
y=yearly_rate_change['Selling rate'],
name='Yearly Change'))
fig.update_layout(title="Yearly Overrall Change(%) of USD againt ZMW Conversion Rate",
xaxis_title="Year",
yaxis_title="Change (%)",
width=900,
height=600)
pio.show(fig)
1 2015 experineced the greatest loss in value of the kwacha depreciating an overrall 41%
2 2016 the kwacha gained an overrall 11% in value
3 through out 2017 and 2019 the kwacha lost value against the dollar with 2020 recording the second largest drop in value of 33%
4 2021 saw largest gain in the exchange rate, with the kwacha appreciating an overrall 27%
# Calculate monthly growth
data['Growth'] = data.groupby(['Year', 'Month'])['Selling rate'].transform(lambda x: (x.iloc[-1] - x.iloc[0]) / x.iloc[-1] *100)
# Group data by Month and calculate average growth
grouped_data = data.groupby('Month').mean().reset_index()
fig = go.Figure()
fig.add_trace(go.Bar(
x=grouped_data['Month'],
y=grouped_data['Growth'],
marker_color=grouped_data['Growth'],
hovertemplate='Month: %{x}<br>Average Growth: %{y:.2f}%<extra></extra>'
))
fig.update_layout(
title="Aggregated Monthly Growth of USD - ZMW Conversion Rate",
xaxis_title="Month",
yaxis_title="Average Growth (%)",
width=900,
height=600
)
pio.show(fig)
From the graph above we can notice that on average the value of the USD is growing in the first quater of the year, drastically reduces in April and has a sharp increament in May. The USD has it greatest gain on avergae during the 3rd Quater of the year with record gains of about 7.13% on average in September. The last Quater of the years sees a steady decline in the value of the USD against the kwacha.
#creating a dataframe of the averge USD/ZMW rates for further analysis
df= data.groupby(['Year', 'Month']).agg({'Selling rate': 'mean'})
df=df.reset_index()
# Pivot the table to have years as columns
df_pivot = df.pivot_table(index='Month', columns='Year', values='Selling rate')
df_pivot
| Year | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Month | |||||||||||
| 1 | 5.297792 | 5.532549 | 6.480154 | 11.138722 | 9.953333 | 9.882109 | 11.958134 | 14.438074 | 21.320744 | 17.288466 | 18.541824 |
| 2 | 5.341868 | 5.696115 | 6.759163 | 11.340276 | 9.787736 | 9.817583 | 11.943695 | 14.715672 | 21.614575 | 18.121685 | 19.430521 |
| 3 | 5.389263 | 6.098510 | 7.367764 | 11.354370 | 9.622815 | 9.610848 | 12.056956 | 16.547235 | 22.010959 | 17.959608 | 20.761374 |
| 4 | 5.369843 | 6.208556 | 7.402171 | 9.753113 | 9.468533 | 9.546208 | 12.329681 | 18.613328 | 22.239085 | 17.418853 | 18.478585 |
| 5 | 5.332128 | 6.627141 | 7.269625 | 10.067181 | 9.280600 | 10.115878 | 13.285192 | 18.249721 | 22.456836 | 17.114484 | 18.607818 |
| 6 | 5.427195 | 6.315078 | 7.340320 | 10.726582 | 9.278523 | 10.069474 | 13.078157 | 18.209666 | 22.605631 | 17.035664 | 18.757500 |
| 7 | 5.491058 | 6.158970 | 7.681049 | 9.926613 | 8.943723 | 9.913695 | 12.770145 | 18.177993 | 21.649682 | 16.448723 | 18.368262 |
| 8 | 5.434596 | 6.118421 | 8.103855 | 10.035591 | 9.043807 | 10.120057 | 13.059671 | 18.807848 | 18.093191 | 16.104730 | NaN |
| 9 | 5.341492 | 6.156435 | 10.209129 | 10.002178 | 9.419757 | 10.976490 | 13.165548 | 19.849005 | 16.398573 | 15.646951 | NaN |
| 10 | 5.327931 | 6.342253 | 12.026660 | 9.906481 | 9.782705 | 11.939002 | 13.203160 | 20.223712 | 17.061367 | 15.947351 | NaN |
| 11 | 5.532100 | 6.355074 | 12.186176 | 9.843612 | 10.066454 | 11.870455 | 14.001909 | 20.859575 | 17.569364 | 16.573000 | NaN |
| 12 | 5.536000 | 6.350156 | 10.848764 | 9.868240 | 10.051031 | 11.937557 | 14.402544 | 21.113726 | 16.808671 | 17.607835 | NaN |
#creating a heat map showing the changes in exchange rates and the colors represent the magnitute of changes
fig = go.Figure(data=go.Heatmap(z=df_pivot.values, x=df_pivot.columns, y=df_pivot.index,
colorscale='Viridis'))
fig.update_layout(title='Exchange Rate Movements - Heatmap',
xaxis_title='Years',
yaxis_title='Months',
xaxis=dict(tickmode='array', tickvals=list(df_pivot.columns)),
yaxis=dict(tickmode='array', tickvals=list(range(1, 13)),
ticktext=['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']),
template='plotly_white')
fig.show()
Showcasing the exchange rate movements over the years per year
fig = make_subplots(rows=6, cols=2,
subplot_titles=("2013 USD/KMW", "2014 USD/KMW", "2015 USD/KMW", "2016 USD/KMW",
"2017 USD/KMW", "2018 USD/KMW", "2019 USD/KMW", "2020 USD/KMW",
"2021 USD/KMW", "2022 USD/KMW", "2023 USD/KMW"))
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 0], mode="lines+markers",name="2013"), row=1, col=1)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 1], mode="lines+markers",name="2014"), row=1, col=2)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 2], mode="lines+markers",name="2015"), row=2, col=1)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 3], mode="lines+markers",name="2016"), row=2, col=2)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 4], mode="lines+markers",name="2017"), row=3, col=1)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 5], mode="lines+markers",name="2018"), row=3, col=2)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 6], mode="lines+markers",name="2019"), row=4, col=1)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 7], mode="lines+markers",name="2020"), row=4, col=2)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 8], mode="lines+markers",name="2021"), row=5, col=1)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 9], mode="lines+markers",name="2022"), row=5, col=2)
fig.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot.iloc[:, 10], mode="lines+markers",name="2023"), row=6, col=1)
fig.update_layout(height=800, width=900, title_text="Movement of USD/KMW over 10 years")
fig.show()